﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Web;

using Rarous.NForms.Validation;

namespace Rarous.NForms {
  /// <summary>
  /// Třída reprezentující formulář.
  /// </summary>
  public class Form : HtmlElement {
    private const bool Secure = true;

    private Dictionary<string, FormItem> items;
    private IFormatter summaryFormatter;

    /// <summary>
    /// Konstruktor. Vytvoří novou instanci Formuláře.
    /// </summary>
    public Form() 
      : this(null) {
    }

    /// <summary>
    /// Konstruktor. Vytvoří novou instanci Form.
    /// </summary>
    /// <param name="request"></param>
    public Form(NameValueCollection data)
      : this(data, (IFormatter)null) {
    }
    /// <summary>
    /// Konstruktor. Vytvoří novou instanci Form.
    /// </summary>
    /// <param name="request"></param>
    public Form(NameValueCollection data, IFormatter summaryFormatter) 
      : this(data, summaryFormatter, null) {
    }
    /// <summary>
    /// Konstruktor. Vytvoří novou instanci Form.
    /// </summary>
    /// <param name="request"></param>
    public Form(NameValueCollection data, List<string> messages)
      : this(data, null, messages) {
    }
    /// <summary>
    /// Konstruktor. Vytvoří novou instanci Form.
    /// </summary>
    /// <param name="request"></param>
    public Form(NameValueCollection data, IFormatter summaryFormatter, List<string> messages)
      : base("form") {
      Data = data ?? new NameValueCollection();
      Messages = messages ?? new List<String>();
      this.summaryFormatter = summaryFormatter ?? new ListValidationSummaryFormatter();
      this.summaryFormatter.Form = this;
      this.items = new Dictionary<string, FormItem>();
    }

    /// <summary>
    /// Indexer. Prochází kolekci formulářových prvků podle jejich názvu.
    /// </summary>
    /// <param name="name">Název formulářvého prvku.</param>
    /// <returns></returns>
    public new FormItem this[string name] {
      get {
        FormItem item = null;
        items.TryGetValue(name, out item);
        return item;
      }
      set {
        items[name] = value;
      }
    }

    public List<string> Messages {
      get;
      set;
    }

    /// <summary>
    /// Vrací kolekci formulářových dat získaných z HTTP požadavku.
    /// </summary>
    public NameValueCollection Data {
      get;
      private set;
    }

    /// <summary>
    /// Vrací příznak, zda je formulář validní.
    /// </summary>
    public bool IsValid {
      get;
      private set;
    }

    /// <summary>
    /// Vrací seznam validačních chyb.
    /// </summary>
    public HtmlElement ValidationSummary {
      get {
        return summaryFormatter.Format();
      }
    }

    #region Hidden
    /// <summary>
    /// Přidá skrytý formulářový prvek.
    /// </summary>
    /// <param name="name">Název formulářeového prvku.</param>
    /// <returns>Vrací referenci na vytvořený prvek.</returns>
    public HiddenItem AddHidden(string name) {
      return new HiddenItem(this, name);
    }
    #endregion

    #region Text
    /// <summary>
    /// Přidá textové formulářové pole.
    /// </summary>
    /// <param name="name">Název formulářeového prvku.</param>
    /// <param name="label">Text popisku formulářového prvku.</param>
    /// <returns>Vrací referenci na vytvořený prvek.</returns>
    public TextItem AddText(string name, string label) {
      return AddText(name, label, null);
    }

    /// <summary>
    /// Přidá textové formulářové pole.
    /// </summary>
    /// <param name="name">Název formulářeového prvku.</param>
    /// <param name="label">Text popisku formulářového prvku.</param>
    /// <param name="size">Velikost textového pole.</param>
    /// <returns>Vrací referenci na vytvořený prvek.</returns>
    public TextItem AddText(string name, string label, int? size) {
      return AddText(name, label, size, null);
    }

    /// <summary>
    /// Přidá textové formulářové pole.
    /// </summary>
    /// <param name="name">Název formulářeového prvku.</param>
    /// <param name="label">Text popisku formulářového prvku.</param>
    /// <param name="size">Velikost textového pole.</param>
    /// <param name="maxLength">Maximální délka textu.</param>
    /// <returns>Vrací referenci na vytvořený prvek.</returns>
    public TextItem AddText(string name, string label, int? size, int? maxLength) {
      TextItem item = new TextItem(this, name, label);
      if (size.HasValue) {
        item.SetAttribute("Size", size);
      }
      if (maxLength.HasValue) {
        item.SetAttribute("MaxLength", maxLength);
      }

      return item;
    }
    #endregion

    #region TextArea
    /// <summary>
    /// Přidá textové formulářové pole.
    /// </summary>
    /// <param name="name">Název formulářeového prvku.</param>
    /// <param name="label">Text popisku formulářového prvku.</param>
    /// <returns></returns>
    public TextAreaItem AddTextArea(string name, string label) {
      return AddTextArea(name, label, 10, 20);
    }

    /// <summary>
    /// Přidá textové formulářové pole.
    /// </summary>
    /// <param name="name">Název formulářeového prvku.</param>
    /// <param name="label">Text popisku formulářového prvku.</param>
    /// <param name="rows">Počet řádků.</param>
    /// <param name="cols">Počet sloupců.</param>
    /// <returns></returns>
    public TextAreaItem AddTextArea(string name, string label, int rows, int cols) {
      return new TextAreaItem(this, name, label, rows, cols);
    }
    #endregion

    #region Password
    public TextItem AddPassword(string name, string label) {
      return AddPassword(name, label, null);
    }

    public TextItem AddPassword(string name, string label, object attributes) {
      return AddPassword(name, label, attributes, null, null);
    }
    public TextItem AddPassword(string name, string label, int? size) {
      return AddPassword(name, label, size, null);
    }

    public TextItem AddPassword(string name, string label, int? size, int? maxLength) {
      return AddPassword(name, label, null, size, maxLength);
    }
    public TextItem AddPassword(string name, string label, object attributes, int? size, int? maxLength) {
      TextItem item = new TextItem(this, name, label, attributes, Secure);
      if (size.HasValue) {
        item.SetAttribute("Size", size);
      }
      if (maxLength.HasValue) {
        item.SetAttribute("MaxLength", maxLength);
      }

      return item;
    }
    #endregion

    #region CheckBox
    public CheckBoxItem AddCheckBox(string name, string label) {
      return AddCheckBox(name, label, false);
    }

    public CheckBoxItem AddCheckBox(string name, string label, bool isChecked) {
      return AddCheckBox(name, label, isChecked, null);
    }

    public CheckBoxItem AddCheckBox(string name, string label, bool isChecked, object attributes) {
      CheckBoxItem item = new CheckBoxItem(this, name, label, attributes);
      if (isChecked) {
        item.SetAttribute("Checked", "checked");
      }
      return item;
    }
    #endregion

    #region Radio
    public RadioItem AddRadio(string name, string label, IEnumerable<ListItem> items) {
      return AddRadio(name, label, items, null);
    }

    public RadioItem AddRadio(string name, string label, IEnumerable<ListItem> items, object attributes) {
      return new RadioItem(this, name, label, items, attributes);
    }
    #endregion

    #region Buttons
    public ButtonItem AddButton(string name, string text) {
      return AddButton(name, text, null);
    }

    public ButtonItem AddButton(string name, string text, object attributes) {
      ButtonItem item = new ButtonItem(this, name, attributes);
      item.SetValue(text);
      return item;
    }

    public ButtonItem AddSubmit(string name, string text) {
      return AddSubmit(name, text, null);
    }

    public ButtonItem AddSubmit(string name, string text, object attributes) {
      ButtonItem item = new ButtonItem(this, name, attributes, InputType.Submit);
      item.SetValue(text);
      return item;
    }

    public ButtonItem AddReset(string name, string text) {
      return AddReset(name, text, null);
    }

    public ButtonItem AddReset(string name, string text, object attributes) {
      ButtonItem item = new ButtonItem(this, name, attributes, InputType.Reset);
      item.SetValue(text);
      return item;
    }

    public ButtonItem AddImage(string name, string src) {
      return AddImage(name, src, null);
    }

    public ButtonItem AddImage(string name, string src, object attributes) {
      ButtonItem item = new ButtonItem(this, name, attributes, InputType.Image);
      item.SetAttribute("Src", src);
      return item;
    }
    #endregion

    #region Select
    public SelectItem AddSelect(string name, string label, IEnumerable<ListItem> items) {
      return AddSelect(name, label, items, null);
    }

    public SelectItem AddSelect(string name, string label, IEnumerable<ListItem> items, object attributes) {
      return new SelectItem(this, name, label, items, attributes);
    }
    #endregion


    private string GetFormValue(string key) {
      if (Data.AllKeys.Contains(key) == false) {
        return String.Empty;
      }
      return Data[key].Trim();
    }

    protected void BindData() {
      foreach (string key in Data.AllKeys) {
        if (items.ContainsKey(key)) {
          FormItem item = items[key];
          item.Value = GetFormValue(key);
          item.SetValue(item.Value);
        }
      }
    }

    /// <summary>
    /// Zvaliduje formulář. Výsledek validace zjistíte přečtením vlastnosti IsValid.
    /// </summary>
    public void Validate() {
      bool result = true;
      foreach (string key in items.Keys) {
        FormItem item = items[key];
        item.Value = GetFormValue(key);
        item.Validate();
        result &= item.IsValid; 
      }
      IsValid = result;
    }

    /// <summary>
    /// Vyrenderuje formulář v tabulce. Vhodné pro testovací účely.
    /// </summary>
    /// <returns></returns>
    public string Render() {
      HtmlElement form = new HtmlElement("form", new { Method = "post", Action = "" });

      StringBuilder sb = new StringBuilder("\n<table>");
      foreach (string key in items.Keys) {
        FormItem item = items[key];
        sb.Append("\n<tr>");
        sb.AppendFormat("\n\t<td>{0}</td>\n\t<td>{1}</td>", item.Label, item.Control);
        sb.Append("\n</tr>");
      }
      sb.AppendLine("\n</table>");
      
      return form.SetHtml(sb.ToString()).ToString();
    }

    // TODO: mozna udelat inteligentni nacitani objektu z requestu
    //public delegate void ObjectFiller<T>(T target, Form form);

    //public void FillObject<T>(T target, ObjectFiller<T> fetch) {
    //  fetch(target, this);
    //}
  }
}